#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/fs.h>

#define KIS_CNT         1
#define KIS_NAME        "kis"
#define KEY_VALUE       0xf0
#define INVALID_VALUE   0x00


struct kis_dev
{
    int major;
    int minor;
    dev_t devid;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct device_node *nd;
    struct timer_list timer;
    unsigned char key_value;        // 按键数值
    int gpio;                       // gpio编号
    int irqnum;                     // 中断号
    irqreturn_t (*handler)(int, void *);
    atomic_t flag;                  // 按键完成标志位
    atomic_t suc;                   //按键是否有效
};
struct kis_dev mydev;

static irqreturn_t kis_handler(int irq, void *dev_id)
{
    struct kis_dev *dev = (struct kis_dev *)dev_id;
    
    dev->timer.data = (volatile long)dev_id;
    mod_timer(&dev->timer, jiffies + msecs_to_jiffies(20));
    return IRQ_RETVAL(IRQ_HANDLED);
}

static void timer_func(unsigned long data)
{
    struct kis_dev *dev = (struct kis_dev *)data;
    unsigned char val;
    val= gpio_get_value(dev->gpio);
    if (val==0)
    {
        printk("111");
        //atomic_set(&dev->key_value,KEY_VALUE);
    }
    else
    {
        printk("222");
        //atomic_set(&dev->flag, 1);
    }
    
}
static int kisdev_init(void)
{
    int val=0;
    printk("key_init\n");
    mydev.nd=of_find_node_by_path("/key");
    printk("111");
    mydev.gpio=of_get_named_gpio(mydev.nd, "key-gpios", 0);
    printk("222");
    gpio_request(mydev.gpio, "kis");
    printk("333");
    gpio_direction_input(mydev.gpio);
    printk("444");
    mydev.irqnum=gpio_to_irq(mydev.gpio);
    printk("555");
    mydev.handler=kis_handler;
    mydev.key_value=KEY_VALUE;
    val = request_irq(mydev.irqnum, kis_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED, "kis", &mydev);
    printk("666");
    if(val < 0){
			printk("irq %d request failed!\r\n", mydev.irqnum);
			return -EFAULT;
		}
    init_timer(&mydev.timer);
    mydev.timer.function=timer_func;

    return 0;
}
static int kis_open(struct inode *inode, struct file *filp)
{
    int ret=0;
    filp->private_data = &mydev;
    ret=kisdev_init();
    if(ret<0){
        return ret;
    }
    return 0;
}
static int kis_release(struct inode *inode, struct file *filp)
{
    return 0;
}
static ssize_t kis_read(struct file *filp, char __user *buf, size_t size, loff_t *off)
{
    struct kis_dev *dev = filp->private_data;
    unsigned char val1 = 0;
    unsigned char val2 = 0;
    int ret=0;

    val1=atomic_read(&dev->suc);
    val2=atomic_read(&dev->flag);
    if(val2){
        if(val1 & 0x80){
            val2 &= ~0x80;
            ret = copy_to_user(buf,&val1,sizeof(val1));
        }else
        {
            goto data_error;
        }
        atomic_set(&dev->flag,0);
    }else
    {
        goto data_error;
    }
    return 0;

data_error:
    return -EINVAL;
    
    
}
static ssize_t kis_write(struct file *filp, const char __user *buf, size_t size, loff_t *off)
{
    return 0;
}
static struct file_operations kis_fops = {
    .owner = THIS_MODULE,
    .open = kis_open,
    .release = kis_release,
    .read = kis_read,
    .write = kis_write,
};
static int __init mykis_init(void)
{
    alloc_chrdev_region(&mydev.devid, 0, 1, "kis");
    mydev.major = MAJOR(mydev.devid);
    mydev.minor = MINOR(mydev.devid);
    cdev_init(&mydev.cdev, &kis_fops);
    cdev_add(&mydev.cdev, mydev.devid, 1);
    mydev.class = class_create(THIS_MODULE, "kis_class");
    mydev.device = device_create(mydev.class, NULL, mydev.devid, NULL, "kis");
    printk("major=%d, minor=%d\n", mydev.major, mydev.minor);
    atomic_set(&mydev.suc, 0);
    atomic_set(&mydev.flag, 0);
    kisdev_init();
    return 0;
}
static void __exit mykis_exit(void)
{
    del_timer(&mydev.timer);
    free_irq(mydev.irqnum, &mydev);
    gpio_free(mydev.gpio);
    cdev_del(&mydev.cdev);
    unregister_chrdev_region(mydev.devid, 1);
    device_destroy(mydev.class, mydev.devid);
    class_destroy(mydev.class);
}
module_init(mykis_init);
module_exit(mykis_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xby");